package com.hliushi.learn.controller;

import com.hliushi.learn.bean.User;
import com.hliushi.learn.response.JsonResult;
import org.springframework.web.bind.annotation.*;

/**
 * @ClassName MVCAnnotationController
 * @Description SpringBoot中的MVC支持
 * @Author hliushi
 * @Date 2021/7/6 10:27
 * @Version V1.0
 **/
@RestController  // @Controller + @ResponseBody
@RequestMapping("/annotation")
public class MvcAnnotationController {


    /**
     * RequestMapping注解使用
     * 该注解常用有三个属性: value, method和produces
     * .    value属性: 指定请求的实际地址
     * .    method属性: 指定请求的类型, 主要有GET, PUT, POSt, DELETE, 默认为GET
     * .    produces属性: 指定返回内容类型, 如produces="application/json;charset=UTF-8"
     *
     * @param
     * @return
     */
    @RequestMapping(value = "/test", produces = "application/json;charset=UTF-8")
    public JsonResult<String> testMethod() {
        return new JsonResult<>();
    }


    /**
     * PathVariable注解使用
     * Path注解主要用来获取url参数, 例如 http://localhost:8001/user/{id}
     *
     * @param
     * @return
     */
    @RequestMapping("/user/{id}/{name}")
    public JsonResult<String> testPathVariable(@PathVariable Integer id, @PathVariable String name) {
        System.out.println("id = " + id + ", name = " + name);

        return new JsonResult<>();
    }


    /**
     * RequestParam获取请求参数的
     * 它是从request里面获取参数值, 即这种url: http:localhost:8001/user?id=1
     * .    required属性: 默认为true !!!, true表示该参数必须要传, 否则就会报404错误, false表示可有可无
     * .    defaultValue属性: 默认值, 表示如果请求中没有同名参数时的默认值
     * .
     *
     * @return
     */
    @RequestMapping("/user")
    public JsonResult<String> testRequestParam(@RequestParam(value = "id", required = false) Integer id) {
        // http://localhost:8001/annotation/user?id=11011&name=hliushi
        // id = 11011
        // http://localhost:8001/annotation/user?name=hliushi
        // id = null
        System.out.println("id = " + id);

        return new JsonResult<>();
    }


    /**
     * @param
     * @return
     */
    @RequestMapping("/form")
    public JsonResult<String> testForm(@RequestParam String username, @RequestParam String password) {
        // http://localhost:8001/annotation/form?username=hliushi&password=qwer1234
        // username = hliushi, password = qwer1234

        /**
         * http://localhost:8001/annotation/form?username=hliushi
         *
         * 所需的字符串参数 'password' 不存在
         * {
         *     "timestamp": "2021-07-06T02:59:55.379+0000",
         *     "status": 400,
         *     "error": "Bad Request",
         *     "message": "Required String parameter 'password' is not present",
         *     "path": "/annotation/form"
         * }
         *
         * POST http://localhost:8001/annotation/form
         * Body -> form-data
         * username: hliushi
         * password: qwer1234
         * #
         * username = hliushi, password = qwer1234
         */
        System.out.println("username = " + username + ", password = " + password);

        return new JsonResult<>();
    }


    /**
     * 注意, 当表单数据很多时候, 我们不可能在后台方法中写入很多参数, 每个参数还要@RequestPararm注解
     * 针对这种情况下, 我们封装一个实体类来接收参数, 实体中的属性名和表单中的参数名一致即可
     * 使用实体接收的话, 我们 --不能再前面加@RequestParam注解--
     *
     * @param user
     * @return
     */
    @RequestMapping("/form/bean")
    public JsonResult<String> testFormBean(User user) {

        // POST/GET http://localhost:8001/annotation/form/bean?username=hliushi
        // user = User{id=null, username='hliushi', password='null'}
        // POST/GET http://localhost:8001/annotation/form/bean?username=hliushi&id=10001
        // user = User{id=10001, username='hliushi', password='null'}

        // POST/GET http://localhost:8001/annotation/form/bean?id=10001&username=hliushi&password=qwer1234&info=nothing
        // user = User{id=10001, username='hliushi', password='qwer1234'}

        // POST http://localhost:8001/annotation/form/bean
        // Body -> form-data
        // id: 1001
        // name: hliushi
        // password: qwer1234
        // user = User{id=1001, username='null', password='qwer1234'}
        System.out.println("user = " + user);
        return new JsonResult<>();
    }


    /**
     * RequestBody 用于接收前端传来的实体, 接收参数也是对应的实体,
     * .           比如前端通过json提交传来两个参数, 此时我们需要在后端封装一个实体来接收
     * .
     * 用来获取请求体的内容 (只有post请求才有请求体body, 所以get请求不适用)
     * 直接使用得到是 key=value&key=value结构的数据
     * .    required属性: 是否必须提供请求体, 默认值是true,
     * .                    当取值为true时, get请求方式会报错, 当取值为false时, get请求得到的是null
     * .
     * #
     * # 时间 2021年7月16日14:35:10
     * # 用于读取Request请求 (可能是Post, PUT, DELETE, GET请求)的 body部分
     * # 并且Content-Type为application/json格式的数据, 接收到数据之后会自动将数据绑定到Java上面去
     * # 系统会使用HttpMessageConverter或者自定义的HttpMessageConverter将请求的body中的JSON字符串转换为Java对象
     * <p>
     * # 注意: 一个请求方法值可以有一个 @RequestBody, 但是可以有多个@RequestParam和@PathVariable
     * .      如果你的方法必须要用到两个@RequestBody来接收数据的话, 大概率是你的数据库设计或者系统设计出现问题了.
     *
     * @return
     */
    @RequestMapping("/requestbody/field")
    public JsonResult<String> testRequestBody(@RequestBody String body) {

        /**
         * POST/GET ---- http://localhost:8001/annotation/requestbody/field
         * Body -> raw -> type=text
         * {
         *     "username": "hliushi",
         *     "password": "qwer1234",
         *     "info": "nothing"
         * }
         * 输出结果
         * body = {
         *     "username": "hliushi",
         *     "password": "qwer1234",
         *     "info": "nothing"
         * }
         */
        System.out.println("body = " + body);


        return new JsonResult<>();
    }


    /**
     * Body -> raw -> type=JSON
     * .    但前台传入的是JSON格式数据会被转换成JavaBean对象格式
     *
     * @param user
     * @return
     */
    @RequestMapping("/requestbody/json")
    public JsonResult<String> testRequestBody2(@RequestBody User user) {

        /**
         * POST --- http://localhost:8001/annotation/requestbody/json
         * Body
         * #raw
         * {
         *     "username":"hliushi",
         *     "password":"qwer1234"
         * }
         *
         * 错误信息
         * {
         *     "timestamp": "2021-07-06T11:43:47.395+0000",
         *     "status": 415,
         *     "error": "Unsupported Media Type",
         *     "message": "Content type 'text/plain;charset=UTF-8' not supported",
         *     "path": "/annotation/requestbody/json"
         * }
         *
         * 注意: SpringBoot 默认使用 Json 作为响应报文格式
         * 解决方式, 将postman工具中的Body -> raw -> 数据格式类型换成 JSON
         */


        // POST/GET -> Body
        // raw  type=JSON
        // {
        //     "username": "hliushi",
        //     "password": "qwer1234",
        //     "info": "nothing"
        // }
        // 输出user = User{id=null, username='hliushi', password='qwer1234'}

        // 2021年7月18日11:08:16, 给User类中password字段添加了@JsonIgnore注解

        // POST  http://localhost:8001/annotation/requestbody/json
        // Body -> raw -> type=JSON
        // {
        //     "username": "hliushi",
        //     "password": "qwer1234",
        //     "info": "nothing"
        // }
        // # 注意下password为null,
        //      当前端以json格式向后台传password的值, 且后台是以实体User接收时
        //      这时候@JsonIngonre会忽略, 即不接受password字段的值
        // #
        //  若想避免此类情况, 建议使用form表单的形式提交参数, 而非json格式
        //  若一定要使用json格式, 可以在定义一个UserDTO类, 传输给前端, 在传输之前将User转为UserDTO
        //  DTO  Data Transfer Object数据传输对象
        //  PO   persistence object 持久化对象  一个PO就是数据库中的一条记录
        //  比如我们有一张表有100个字段, 那么对应的PO就有100个属性, 但是我们页面上只需要显示10个字段
        //  客户端用WEB service来获取数据, 没必要把整个PO对象传给客户端
        //  这时我们就可以用只有10个属性的DTO传递结果到客户端, 这样也不会暴露服务端表结构
        //  到达客户端以后, 如果用这个对象来对应界面显示, 那此时他的身份就转为VO
        //
        // 输出user = User{id=null, username='hliushi', password='null'}

        System.out.println("user = " + user);

        return new JsonResult<>();
    }

}
